home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / overview / dave falkenburg's sprocket / lib / dialogutils.cp < prev    next >
Encoding:
Text File  |  2000-09-28  |  11.0 KB  |  415 lines

  1. /*
  2.     File:        DialogUtils.cp
  3.  
  4.     Contains:    Auto-sized error alert mechanism,
  5.                 ModalFilterProcs which correctly handle events,
  6.                 and Standard “Close Document” dialogs. 
  7.  
  8.     Written by: Dave Falkenburg    
  9.  
  10.     Copyright:    Copyright © 1993-1999 by Apple Computer, Inc., All Rights Reserved.
  11.  
  12.                 You may incorporate this Apple sample source code into your program(s) without
  13.                 restriction. This Apple sample source code has been provided "AS IS" and the
  14.                 responsibility for its operation is yours. You are not permitted to redistribute
  15.                 this Apple sample source code as "Apple sample source code" after having made
  16.                 changes. If you're going to re-distribute the source, we require that you make
  17.                 it clear in the source that the code was descended from Apple sample source
  18.                 code, but that you've made changes.
  19.  
  20.     Change History (most recent first):
  21.                 8/19/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  22.                 11/23/94    DRF                Add ToggleCheckBox, a nice little dialog item utility.
  23.                 11/16/94    DRF                Added explicit #include <SegLoad.h> for latest universal
  24.                                             headers. Also added cast to keep MPW CFront happier.
  25.                 11/16/94    DRF                Add StdFilterProc for THINK C.
  26.                 9/27/94        DRF                 AppLib.h is now Sprocket.h
  27.                 9/9/94        DRF                Reordered headers and removed redundant #includes.
  28.  
  29. */
  30.  
  31. #include "Sprocket.h"
  32.  
  33. #include <Fonts.h>
  34. #include <Resources.h>
  35. #include <TextUtils.h>
  36. #include <Threads.h>        //    For YieldToAnyThread()
  37. #include <StandardFile.h>    //    For ModalFilterYDProcPtr
  38. #include <SegLoad.h>        //    For ExitToShell()
  39.  
  40. //    Some types which should probably be defined in <Dialogs.h>
  41. //    NOTE: These must be aligned on 2-byte boundaries
  42. #if defined(powerc) || defined (__powerc)
  43. #pragma options align=mac68k
  44. #endif
  45.  
  46. struct DialogItem
  47.     {
  48.     long    usedByDialogManager;
  49.     Rect    boundsRect;
  50.     char    type;
  51.     char    length;
  52.     };
  53.  
  54. struct DialogItemList            //    a.k.a. a 'DITL'
  55.     {
  56.     short        count;
  57.     DialogItem    firstItem[1];
  58.     };
  59.  
  60. //    Restore default alignment
  61. #if defined(powerc) || defined(__powerc)
  62. #pragma options align=reset
  63. #endif
  64.  
  65. typedef    DialogItem        *DialogItemPtr;
  66. typedef    DialogItemList    **DialogItemListHandle;
  67. typedef    DialogTemplate    **DialogTemplateHandle;
  68.  
  69. #ifndef    powerc
  70. #ifdef    __SC__
  71.  
  72. extern pascal OSErr GetStdFilterProc(ModalFilterUPP *theProc)
  73.  THREEWORDINLINE(0x303C, 0x0203, 0xAA68);
  74.  
  75. pascal Boolean
  76. StdFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  77.     {
  78.     ModalFilterUPP    filterUPP;
  79.  
  80.     //    Dialogs.h
  81.     
  82.     (void) GetStdFilterProc(&filterUPP);
  83.  
  84.     return    CallModalFilterProc(filterUPP,theDialog,anEvent,itemHit);
  85.     }
  86.  
  87. #endif
  88. #endif
  89.  
  90. //    private function Prototypes
  91.  
  92. static    pascal Boolean    StandardDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  93. static    pascal Boolean    StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit, void * yourData);
  94. static    pascal Boolean    StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  95. static    Boolean            FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  96.  
  97.  
  98.  
  99. ///////////////////////////////////////////////////////////
  100. //
  101. //    StandardAlert
  102. //
  103. //    An alternative to Alert() which uses the extended
  104. //    Dialog Manager capabilities.
  105. //
  106. //    I’m not sure we really need this call, but it seems
  107. //    to do the trick just fine.
  108.  
  109. short
  110. StandardAlert(    short dlogID,
  111.                 short defaultItem,                /* = ok */
  112.                 short cancelItem,                /* = 0 */
  113.                 ModalFilterUPP customFilterProc    /* = nil */)
  114.     {
  115.     DialogPtr        theDialog;
  116.     short            itemHit = 0;
  117.     ModalFilterUPP    filterToUse;
  118.     
  119.     HiliteWindowsForModalDialog(false);
  120.  
  121.     theDialog = GetNewDialog(dlogID,nil,(WindowPtr) -1);
  122.     if (defaultItem)
  123.         SetDialogDefaultItem(theDialog,defaultItem);
  124.     if (cancelItem)
  125.         SetDialogCancelItem(theDialog,cancelItem);
  126.  
  127.     if (customFilterProc)
  128.         filterToUse = customFilterProc;
  129.     else
  130.         filterToUse = StandardDialogFilter;
  131.  
  132.     do
  133.         ModalDialog(filterToUse,&itemHit);
  134.     while (itemHit == 0);
  135.     
  136.     DisposeDialog(theDialog);
  137.  
  138.     HiliteWindowsForModalDialog(true);
  139.  
  140.     return itemHit;
  141.     }
  142.  
  143.  
  144. ///////////////////////////////////////////////////////////
  145. //
  146. //    ErrorAlert
  147. //
  148. //    A nice error reporting routine which presents an
  149. //    auto-sized alert box containing the supplied text.
  150. //
  151. //    NOTE:    This routine ASSUMES the following 'DITL'
  152. //            structure:
  153. //
  154. //            item #1 : an “OK” button
  155. //            item #2 : a static text item, somewhere above #1
  156. //
  157. //    NOTE:    We probably need to worry more about low
  158. //            memory conditions-- this can probably
  159. //            be handled by a custom GrowZoneProc and
  160. //            reserve memory area large enough to hold
  161. //            all the space we’d need.
  162. //
  163.  
  164. void
  165. ErrorAlert(short stringList,short whichString)
  166.     {
  167.     Str255                    errorString;
  168.     GrafPtr                    oldPort,windowMgrPort;
  169.     short                    oldFont;
  170.     DialogTemplateHandle    errorDialogTemplate;
  171.     DialogItemListHandle    errorDialogItems;
  172.     TEHandle                aTEHandle;
  173.     Rect                    textRect;
  174.     short                    textHeight;
  175.     short                    additionalSpaceNeeded;
  176.     DialogItemPtr            okButtonItem,errorTextItem;
  177.     const StringPtr            nullStr = (StringPtr) "\p";
  178.  
  179.     GetIndString(errorString,stringList,whichString);
  180.     
  181.     errorDialogTemplate = (DialogTemplateHandle) Get1Resource('DLOG',kErrorAlertID);
  182.     HLock((Handle) errorDialogTemplate);
  183.     
  184.     errorDialogItems = (DialogItemListHandle) Get1Resource('DITL',(**errorDialogTemplate).itemsID);
  185.     HLock((Handle) errorDialogItems);
  186.     
  187.     //    Find the dialog items
  188.     
  189.     okButtonItem = (**errorDialogItems).firstItem;
  190.     errorTextItem = (DialogItemPtr) ((Ptr) okButtonItem + sizeof(DialogItem) + okButtonItem->length);
  191.     
  192.     GetPort(&oldPort);
  193.     GetWMgrPort(&windowMgrPort);
  194.     SetPort(windowMgrPort);
  195.     oldFont = qd.thePort->txFont;
  196.     TextFont(systemFont);
  197.  
  198.     aTEHandle = TENew(&textRect,&textRect);
  199.     TESetText(&errorString[1],errorString[0],aTEHandle);
  200.     textHeight = (*aTEHandle)->lineHeight * (*aTEHandle)->nLines;
  201.     TEDispose(aTEHandle);
  202.  
  203.     additionalSpaceNeeded = textHeight - (errorTextItem->boundsRect.bottom
  204.                             - errorTextItem->boundsRect.top);
  205.  
  206.     if (additionalSpaceNeeded > 0)
  207.         {
  208.         (**errorDialogTemplate).boundsRect.bottom += additionalSpaceNeeded;
  209.         errorTextItem->boundsRect.bottom += additionalSpaceNeeded;
  210.         OffsetRect(&okButtonItem->boundsRect,0,additionalSpaceNeeded);
  211.         }
  212.         
  213.     TextFont(oldFont);
  214.     SetPort(oldPort);
  215.     
  216.     InitCursor();
  217.     ParamText(errorString,nullStr,nullStr,nullStr);
  218.  
  219.     (void) StandardAlert(kErrorAlertID);
  220.  
  221.     ReleaseResource((Handle) errorDialogTemplate);
  222.     ReleaseResource((Handle) errorDialogItems);
  223.     }
  224.  
  225.  
  226. ///////////////////////////////////////////////////////////
  227. //
  228. //    FatalErrorAlert
  229. //
  230. //    A companion to ErrorAlert which also kills the process.
  231. //
  232.  
  233. void
  234. FatalErrorAlert(short stringList,short whichString)
  235.     {
  236.     ErrorAlert(stringList,whichString);
  237.     ExitToShell();
  238.     }
  239.  
  240.  
  241. ///////////////////////////////////////////////////////////
  242. //
  243. //    StandardDialogFilter and StandardDialogFilterYD
  244. //
  245. //    These function takes care of routing events not meant
  246. //    for the dialog window to other parts of the application.
  247. //
  248. //    Use them as an alternative to passing a NIL ModalFilterProc
  249. //    to ModalDialog() and CustomGet(Put)File. Unlike the default
  250. //    filter, these routines properly processes update events
  251. //    to keep background processes running.
  252. //
  253. //    The Thread Manager, if present, is also called to yield
  254. //    control to other cooperative threads within the process.
  255. //
  256. //    Because of pascal calling conventions we need two separate
  257. //    routines, but this is minimized by sharing implementation
  258. //    in FilterProcCommon.
  259. //
  260.  
  261. ModalFilterUPP    StandardDialogFilter
  262. = NewModalFilterProc(StandardDialogFilterProc);
  263.  
  264. ModalFilterYDUPP    StandardDialogFilterYD
  265. = NewModalFilterYDProc(StandardDialogFilterYDProc);
  266.  
  267. ModalFilterUPP    StandardCloseDialogFilter
  268. = NewModalFilterProc(StandardCloseDialogFilterProc);
  269.  
  270.  
  271. pascal Boolean
  272. StandardDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  273.     {
  274.     //    Call through common code to check for events we’d like to handle.
  275.     //    If that is unsuccessful, call through the System 7 StdFilterProc
  276.     //    to handle CR, “CMD-.” & ESC in an international-friendly manner.
  277.  
  278.     if (FilterProcCommon(theDialog, anEvent, itemHit))
  279.         return true;
  280.     else
  281.         return (StdFilterProc(theDialog, anEvent, itemHit));
  282.     }
  283.  
  284.  
  285. pascal Boolean
  286. StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit, void * /*unusedData*/)
  287.     {
  288.     //    We don’t call through to StdFilterProc since the
  289.     //    Standard File Package already does everything we need.
  290.  
  291.     return FilterProcCommon(theDialog, anEvent, itemHit);
  292.     }
  293.  
  294. void
  295. PseudoClickInDialogItem(DialogPtr theDialog, short itemToClick)
  296.     {
  297.     Handle    itemHandle;
  298.     Rect    itemBox;
  299.     unsigned long    finalTicks;
  300.     short    itemType;
  301.     
  302.     GetDialogItem(theDialog,itemToClick,&itemType,&itemHandle,&itemBox);
  303.  
  304.     HiliteControl((ControlHandle) itemHandle,kControlButtonPart);
  305.     Delay(8,&finalTicks);
  306.     HiliteControl((ControlHandle) itemHandle,0);
  307.     }
  308.  
  309.  
  310. Boolean
  311. ToggleCheckBox(DialogPtr theDialog, short theCheckBox)
  312.     {
  313.     ControlHandle    itemHandle;
  314.     Rect            itemBox;
  315.     short            itemType;
  316.     
  317.     GetDialogItem(theDialog,theCheckBox,&itemType,(Handle *) &itemHandle,&itemBox);
  318.  
  319.     if (GetControlValue(itemHandle) == 1)
  320.         {
  321.         SetControlValue(itemHandle,0);
  322.         return false;
  323.         }
  324.     else
  325.         {
  326.         SetControlValue(itemHandle,1);
  327.         return true;
  328.         }
  329.     }
  330.  
  331.  
  332. pascal Boolean
  333. StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  334.     {
  335.     if ((anEvent->what == keyDown))
  336.         {
  337.         char    c = (char) anEvent->message & charCodeMask;
  338.         
  339.         if ((c == 'd') || (c == 'D'))                //    NOT INTERNATIONAL FRIENDLY!!!
  340.             {
  341.             *itemHit = kDontSaveDocument;
  342.             PseudoClickInDialogItem(theDialog,kDontSaveDocument);
  343.             return true;
  344.             }
  345.         }
  346.  
  347.     //    Return through the common code above so that default item processing can happen
  348.     return StandardDialogFilterProc(theDialog, anEvent, itemHit);
  349.     }
  350.  
  351.  
  352. Boolean
  353. FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * /* itemHit */)
  354.     {
  355.     switch (anEvent->what)
  356.         {
  357.         case updateEvt:
  358.         case activateEvt:
  359.             //     Update or activate for the dialog window?
  360.             if (theDialog == (DialogPtr) anEvent->message)
  361.                 break;
  362.  
  363.             //    no, fall through to HandleEvent            
  364.             
  365.         case diskEvt:
  366.             HandleEvent(anEvent);
  367.             return(false);
  368.  
  369.         default:
  370.             break;        
  371.         }
  372.  
  373.     if (gHasThreadManager)        //    If we have threads, let them run!
  374.         YieldToAnyThread();
  375.  
  376.     return false;                //    We didn’t handle the event
  377.     }
  378.  
  379.  
  380. //////////////////////////////////////////////////////////////////
  381. //
  382. //    StandardCloseDocument
  383. //
  384. //    Provides the standard human interface for closing a document
  385. //
  386. //    NOTE: When we make TDocument class, this will become a method
  387. //          and probably won’t need any parameters.
  388. //
  389. //    NOTE:    StandardCloseResult matches the dialog items for 
  390.  
  391. StandardCloseResult
  392. StandardCloseDocument(const StringPtr documentType, StringPtr documentName,
  393.                       Boolean hasNewEditions, Boolean quitting)
  394.     {
  395.     short        whichAlert;
  396.     short        whichString;
  397.     StringPtr    nullStr = (StringPtr) "\p";
  398.     Str255        reasonForClosingStr;
  399.  
  400.     if (hasNewEditions)
  401.         whichAlert = kStandardCloseWithNewPubsAlertID;
  402.     else
  403.         whichAlert = kStandardCloseAlertID;
  404.     
  405.     if (quitting)
  406.         whichString = kQuittingStr;
  407.     else
  408.         whichString = kClosingStr;
  409.  
  410.     GetIndString(reasonForClosingStr,kStandardCloseStrings,whichString);
  411.     ParamText(documentType,documentName,reasonForClosingStr,nullStr);
  412.     
  413.     return ((StandardCloseResult) StandardAlert(whichAlert,kSaveDocument,kCancelSaveDocument,StandardCloseDialogFilter));
  414.     }
  415.